#region Using Statements

using System.Collections.Generic;
using System.Collections;
using System.Collections.ObjectModel;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using ZombieHigh2.GameState;
using ZombieHigh2.Actor;
using ZombieHigh2.World;
using ZombieHigh2.Interfaces;
using ZombieHigh2.Audio;
using ZombieHigh2.Stats;
using ZombieHigh2.Viewport;
using Microsoft.Xna.Framework.Input;
using System;
using ZombieHigh2.Parser;
using ZombieHigh2.DeleD;
using ZombieHigh2.GameInput;
using System.Xml;
using System.Threading;
using ParticleSystem.Particles;
using QuadAnimation.Animation;
using QuadAnimation.Primitives.Shapes;
using QuadAnimation.Animation.XML;
#endregion

namespace ZombieHigh2.Screens
{
    /// <summary>
    /// States used by the GameScreen
    /// </summary>
    public enum GameStates
    {
        LOADING,
        PLAYING,
        PAUSED,
        BOSS_INTRO,
        BOSS_BATTLE,
        LEVEL_OVER
    }

    public class Constants
    {
        public static float COMBO_TIME = 1.5f;
    }

    public class GameScreen : IGameState, ActionEvents
    {
        #region Member Variables
        ContentManager content;
        Matrix view;
        Matrix projectionMatrix;
        VertexDeclaration vertexDeclaration;
        Texture2D playerTexture;
        HumanPlayer player;
        Texture2D zombieOneTex;
        GraphicsDevice device;

        List<Monster> monsters;
        AudioSystem Audio;

        //This is for debugging purposes
        short[] debug_lineListIndices = { 0, 1, 2, 3, 4, 5, 6, 7 };
        VertexPositionNormalTexture[] debug_vertices = new VertexPositionNormalTexture[8];

        LevelStats PlayerLevelStats;

        Texture2D health_tex;
        Texture2D hudSlots;
        Texture2D hudItemSprayCan;
        SpriteBatch sb;

        GameStates currentGameState;
        GameStates previousGameState;

        Texture2D overlay;
        int playerHitComboCounter = 0;      //Combo counter
        float comboTimeUp = 0f;
        VertexPositionNormalTexture[] points = new VertexPositionNormalTexture[4];
        DeledParser parser;
        Texture2D[] materials;
        List<int> nonDrawableMaterials;
        Effect shader;

        List<WorldItem> worldItems;
        Model knifeModel;
        Model canModel;

        WorldData worldLoader;
        float testValue = 0f;
        RandomBurstParticleEmitter sparkEmitter;
        StaticParticleEmitter smokeEmitter;
        List<StaticParticleEmitter> staticEmitters;
        Matrix viewMatrix;
        #endregion

        #region Public Properties
        public ContentManager Content
        {
            get { return content; }
        }

        public bool IsPaused
        {
            get { return false; }
        }
        #endregion

        #region Constructors
        public GameScreen(ContentManager content)
        {
            this.content = content;
            currentGameState = GameStates.LOADING;
            previousGameState = GameStates.LOADING;
            overlay = null;
            nonDrawableMaterials = new List<int>();
        }
        #endregion

        #region Loading Methods
        public void UnloadGraphics()
        {
        }

        /// <summary>
        /// Initializes everything that is important to the game here.
        /// </summary>
        void InitializeSubSystems()
        {
            //Initialize the audio
            Audio = new AudioSystem();
            Audio.Initialize();
        }

        /// <summary>
        /// Loads the graphics and assets that are necessary to executing the game.
        /// </summary>
        /// <param name="device">The GraphicsDevice object.</param>
        public void LoadGraphics(GraphicsDevice device)
        {
            this.device = device;
            InitializeSubSystems();
            device.RenderState.CullMode = CullMode.CullCounterClockwiseFace;

            sparkEmitter = new RandomBurstParticleEmitter(ZEngine.sparkParticleSystem, new Vector3(100,100,100), Vector3.Up);
            //smokeEmitter = new StaticParticleEmitter(ZEngine.smokeParticleSystem, new Vector3(100, 1, 10), new Vector3(0, 10, 0));

            //Our spritebatch for the overlays
            sb = new SpriteBatch(device);

            //Setup our vertex declaration
            //since we are only using VertexPositionNormalTexture types, we can set
            //it up here and never worry about it again.
            vertexDeclaration = new VertexDeclaration(device, VertexPositionNormalTexture.VertexElements);

            //Setup the matricies
            view = Matrix.CreateLookAt(new Vector3(0, 384, 968), new Vector3(0, 0, 0), Vector3.Up);
            projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, 4.0f / 3.0f, 1, 4096);

            //Load the specific assets that apply to all states
            shader = content.Load<Effect>(@"Data\Shaders\shader");

            /***
             * Texture assets
             * */
            //Player and monster specific assets
            playerTexture = content.Load<Texture2D>(@"Data\Images\player_cycles");
            zombieOneTex = content.Load<Texture2D>(@"Data\Images\actor_zombie");
            hudSlots = content.Load<Texture2D>(@"Data\Images\hud");
            hudItemSprayCan = content.Load<Texture2D>(@"Data\Images\hud_item_spraycan");

            //Load the level
            parser = new DeledParser();

            worldLoader = new WorldData(parser);
            worldLoader.OnLoadComplete += OnLoadComplete;

            LoadLevel("test.xml");

        }

        public void Load()
        {
        }

        /// <summary>
        /// Loads a model and sets the effect to the current shader used.
        /// </summary>
        /// <param name="model">A reference to the model to load.</param>
        /// <param name="asset">The path to the texture used by the model.</param>
        void LoadModel(out Model model, String asset, ref BoundingSphere boundingSphere)
        {
            model = content.Load<Model>(asset);

            foreach (ModelMesh modmesh in model.Meshes)
            {
                boundingSphere = modmesh.BoundingSphere;
                foreach (ModelMeshPart modmeshpart in modmesh.MeshParts)
                {
                    modmeshpart.Effect = shader.Clone(device);
                }
            }
        }

        public void LoadEnemies()
        {
        }

        /// <summary>
        /// This method is called when Loading of the world data by the
        /// WorldData thread is complete.
        /// </summary>
        void OnLoadComplete()
        {
            Vector3 playerSpawn = Vector3.Zero;
            previousGameState = currentGameState;
            currentGameState = GameStates.PLAYING;

            //Load the materials based on the level data
            materials = new Texture2D[worldLoader.Parser.Materials.Count];
            for (int i = 0; i < worldLoader.Parser.Materials.Count; i++)
            {
                String texturename = ((Material)worldLoader.Parser.Materials[i]).texturename;
                texturename = texturename.Substring(0, texturename.Length - 4);
                //if (texturename.Equals("System\\system"))
                //    nonDrawableMaterials.Add(i);

                materials[i] = content.Load<Texture2D>(@"Data\Textures\" + texturename);
            }

            ////////////////////////////////////////////////////////////////////
            //This loads the aniamtions associated with each frame
            //Load the player information
            Quad playerQuad = new Quad(Vector3.Zero, Vector3.Backward, Vector3.Up, 96, 128);
            AnimationSettings animationSettings = new AnimationSettings();
            XMLAnimationLoader.LoadAnimationSettings(@"Data\Animations\player.xml", ref animationSettings, content);
            AnimatedObject playerAnimation = new AnimatedObject(playerQuad, animationSettings);
            monsters = new List<Monster>();
            player = new HumanPlayer(this, Audio, playerAnimation);
            ////////////////////////////////////////////////////////////////////

            //Read PLAYER SPAWN point from map
            playerSpawn = parser.PlayerSpawn;

            //Read NUMBER OF MONSTERS and each SPAWN POINT
            List<Vector3> zombieSpawns = worldLoader.Parser.ZombieSpawns;
            foreach (Vector3 loc in zombieSpawns)
            {
                Quad zombieQuad = new Quad(Vector3.Zero, Vector3.Backward, Vector3.Up, 96, 128);
                AnimationSettings zombieAnimationSettings = new AnimationSettings();
                XMLAnimationLoader.LoadAnimationSettings(@"Data\Animations\player.xml", ref zombieAnimationSettings, content);
                AnimatedObject zombieAnimation = new AnimatedObject(zombieQuad, zombieAnimationSettings);

                ZombieOne zombie = new ZombieOne(this, Audio, zombieAnimation);
                zombie.Pos = loc;
                monsters.Add(zombie);
            }

            //Read BOSS location (if any)

            //Read Triggers

            //Read the particle emmitters
            staticEmitters = parser.StaticEmitters;

            //Read ITEMS
            worldItems = new List<WorldItem>();
            foreach (WorldItem witem in worldLoader.Parser.Items)
            {
                BoundingSphere bsphere = new BoundingSphere();

                switch (witem.ItemType)
                {
                    case WorldConstants.WEAPON_CAN:
                        LoadModel(out canModel, @"Data\Models\weapon_can", ref bsphere);
                        witem.BoundingSphere = bsphere;
                        break;

                    case WorldConstants.WEAPON_KNIFE:
                        LoadModel(out knifeModel, @"Data\Models\weapon_knife", ref bsphere);
                        witem.BoundingSphere = bsphere;
                        break;
                }

                worldItems.Add(witem);
            }

            //Now initialize all items


            //Initialize the monster systems
            player.Pos = playerSpawn;
            player.Load();

            foreach (Monster monster in monsters)
            {
                monster.Load();
            }

            PlayerLevelStats = new LevelStats();
        }

        void LoadLevel(String levelName)
        {
            worldLoader.SetLevelToLoad(levelName);
            Thread worldDataThread = new Thread(new ThreadStart(worldLoader.Load));
            worldDataThread.Start();
        }
        #endregion

        public void Update(GameTime gameTime)
        {
            ZEngine.sparkParticleSystem.SetCamera(viewMatrix, projectionMatrix);
            ZEngine.smokeParticleSystem.SetCamera(viewMatrix, projectionMatrix);
            sparkEmitter.Update(gameTime);

            if (staticEmitters != null)
            {
                foreach (StaticParticleEmitter static_emitter in staticEmitters)
                {
                    static_emitter.Update(gameTime);
                }
            }
            //smokeEmitter.Update(gameTime);

            float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds;
            InputManager.Instance.Update();
            testValue += 0.25f * elapsedTime;
            if (testValue > 1.0f)
                testValue = 0.0f;

            /* What is the current game state? */
            if (currentGameState == GameStates.PLAYING)
            {
                GameState_Playing(gameTime, elapsedTime);
            }
            else if (currentGameState == GameStates.PAUSED)
            {
                GameState_Paused(elapsedTime);
            }

        }

        #region DRAWING ROUTINES
        public void Draw(GraphicsDevice device)
        {
            device.Clear(Color.Black);

            if (currentGameState == GameStates.PLAYING)
            {
                DrawPlayingState(device);
            }

        }

        /// <summary>
        /// Called when the game is being played.
        /// </summary>
        /// <param name="device"></param>
        void DrawPlayingState(GraphicsDevice device)
        {
            
            device.RenderState.AlphaTestEnable = true;
            device.RenderState.AlphaFunction = CompareFunction.Greater;
            device.RenderState.AlphaBlendEnable = true;
            device.VertexDeclaration = vertexDeclaration;

            viewMatrix = Matrix.CreateLookAt(player.Pos + new Vector3(0, 256, 700), player.Pos, Vector3.Up);

            shader.CurrentTechnique = shader.Techniques["simple"];
            shader.Parameters["xView"].SetValue(viewMatrix);
            shader.Parameters["xProjection"].SetValue(projectionMatrix);

            //shader.Parameters["lightDir"].SetValue(new Vector4(1, 1, 1, 0));
            shader.Parameters["xLightPos"].SetValue(new Vector4(200, 500, 1000, 0));
            shader.Parameters["ambientColor"].SetValue(new Vector4(0.5f, 0.5f, 0.5f, 0f));
            shader.Parameters["xEyePos"].SetValue(new Vector4(player.Pos + new Vector3(0, 256, 700), 0));
            shader.Parameters["xLightColor"].SetValue(new Vector4(1, 1, 1, 1));

            //Being our drawing process
            shader.Begin();
            foreach (EffectPass pass in shader.CurrentTechnique.Passes)
            {
                shader.Parameters["xWorld"].SetValue(Matrix.CreateTranslation(player.Pos));
                shader.Parameters["xTexture"].SetValue(playerTexture);
                pass.Begin();
                player.Draw(device);
                pass.End();

                foreach (Monster monster in monsters)
                {
                    if (!monster.IsDead)
                    {
                        shader.Parameters["xWorld"].SetValue(Matrix.CreateTranslation(monster.Pos));
                        shader.Parameters["xTexture"].SetValue(zombieOneTex);
                        pass.Begin();
                        monster.Draw(device);
                        pass.End();
                    }
                }

                //Draw any special effects
                shader.Parameters["xWorld"].SetValue(Matrix.Identity);
                pass.Begin();
                //DrawBlood(player.Pos, device);
                pass.End();

                //Draw the world!
                foreach (ZombieHigh2.DeleD.Primitive3D prim in parser.Primitives)
                {
                    DrawPrimitive(device, prim, shader, pass);
                }
            }
            shader.End();

            //Draw the Items
            Model itemModel = null;
            foreach (WorldItem witem in worldItems)
            {
                itemModel = null;
                switch (witem.ItemType)
                {
                    case WorldConstants.WEAPON_CAN:
                        itemModel = canModel;
                        break;

                    case WorldConstants.WEAPON_KNIFE:
                        itemModel = knifeModel;
                        break;

                }

                if (itemModel != null)
                    DrawModel(itemModel, viewMatrix, projectionMatrix, witem.Position);
            }

            //This must be drawn last!
            DrawPlayerHUD();

            if (overlay != null)
            {
                sb.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);
                sb.Draw(overlay, new Vector2(0, 0), Color.White);
                sb.End();
            }
        }

        /// <summary>
        /// Called when the game is loading world data.
        /// </summary>
        /// <param name="device"></param>
        void DrawLoadingState(GraphicsDevice device)
        {
        }

        void DrawBlood(Vector3 position, GraphicsDevice device)
        {
            device.RenderState.PointSize = 10;
            points[0] = new VertexPositionNormalTexture(position, Vector3.Forward, Vector2.Zero);
            points[1] = new VertexPositionNormalTexture(position + new Vector3(0, 10, 0), Vector3.Forward, Vector2.Zero);
            points[2] = new VertexPositionNormalTexture(position - new Vector3(0, 10, 0), Vector3.Forward, Vector2.Zero);
            points[3] = new VertexPositionNormalTexture(position + new Vector3(10, 10, 10), Vector3.Forward, Vector2.Zero);

            device.DrawUserPrimitives<VertexPositionNormalTexture>(PrimitiveType.PointList, points, 0, 4);

        }

        private void DrawModel(Model m, Matrix view, Matrix projection, Vector3 position)
        {
            Matrix[] transforms = new Matrix[m.Bones.Count];
            m.CopyAbsoluteBoneTransformsTo(transforms);
            //Matrix MyWorldRotation = Matrix.Identity;

            foreach (ModelMesh mesh in m.Meshes)
            {
                foreach (Effect effect in mesh.Effects)
                {
                    effect.CurrentTechnique = effect.Techniques["simple"];
                    effect.Parameters["xView"].SetValue(view);
                    effect.Parameters["xProjection"].SetValue(projection);
                    effect.Parameters["xTexture"].SetValue(content.Load<Texture2D>(@"Data\Models\can_uv"));
                    effect.Parameters["ambientColor"].SetValue(new Vector4(1, 1, 1, 0));
                    effect.Parameters["xWorld"].SetValue(Matrix.CreateScale(25f) * transforms[mesh.ParentBone.Index] * Matrix.CreateTranslation(position));
                }
                mesh.Draw();
            }
        }

        void DrawPrimitive(GraphicsDevice device, ZombieHigh2.DeleD.Primitive3D primitive, Effect effect, EffectPass pass)
        {
            effect.Parameters["xWorld"].SetValue(Matrix.Identity);
            foreach (TexturedPolygon texPoly in primitive.polygons)
            {
                //if (!nonDrawableMaterials.Contains(texPoly.materialID))
                {
                    //effect.Texture = materials[texPoly.materialID];
                    //effect.Parameters["xTexture"].SetValue(materials[texPoly.materialID]);
                    effect.Parameters["xTexture"].SetValue(content.Load<Texture2D>(@"Data\Textures\Walls\Wall01"));
                    pass.Begin();
                    device.DrawUserPrimitives<VertexPositionNormalTexture>(PrimitiveType.TriangleFan, texPoly.GetVertices(), 0, (texPoly.GetVertices().Length * 2 - 1) / 3);
                    pass.End();
                }
            }

        }

        void DrawPlayerHUD()
        {
            int w, h;
            Vector2 pos = new Vector2();
            Vector2 hudSlotsPos;
            Vector2 hudItemSprayCanPos;

            health_tex = content.Load<Texture2D>(@"Data\Images\health_grade_D");
            w = health_tex.Width;
            h = health_tex.Height;

            ViewportInfo viewInfo = ViewportInfo.Instance;
            pos.X = 0;
            pos.Y = viewInfo.GetHeight - h - 1;

            hudSlotsPos = pos;
            hudSlotsPos.X += w + 40;

            hudItemSprayCanPos = hudSlotsPos;
            hudItemSprayCanPos.X += 67;

            sb.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);
            sb.Draw(health_tex, pos, Color.White);
            sb.Draw(hudSlots, hudSlotsPos, Color.White);

            if (player.Inventory.HasSprayCan)
            {
                sb.Draw(hudItemSprayCan, hudItemSprayCanPos, Color.White);
            }

            sb.End();
        }

        #endregion

        #region Loading Methods
        

        /// <summary>
        /// Causes all loaded world objects, like items and players to drop to 
        /// the ground.
        /// </summary>
        void DropWorldObjectsToGround()
        {
            
        }
        #endregion

        /// <summary>
        /// Checks for specific events in the game and throws them
        /// when found.
        /// </summary>
        void FireEvents()
        {
            //zombieOne.PlayerLocation(zombieOne.Pos, player.Pos);
            foreach (Monster monster in monsters)
            {
                monster.Info_PlayerLocation(player.Pos);

                if (monster.IdleTime <= 0)
                {
                    monster.Info_IdleTimeUp();
                }

                if (monster.StunTime <= 0)
                {
                    monster.Info_StunTimeUp();
                }
            }
        }

        /// <summary>
        /// Check to see if any of the Actors have requested to perform
        /// some action and react accordingly.
        /// </summary>
        void CheckActions()
        {
            //if (player.Attacking)
            //{
            //    player.Attacking = false;
            //    if (player.CurrentState != PlayerState.PSTATE_ATTACKING)
            //    {
            //        player.CurrentState = PlayerState.PSTATE_ATTACKING;
            //        player.SetAnimationCycle("Attack");
            //    }
            //    else
            //        player.CurrentState = PlayerState.PSTATE_ATTACKING;
            //}

            //if (zombieOne.CurrentState != PlayerState.PSTATE_WALKING)
            //{
            //    zombieOne.SetAnimationCycle("Walk");
            //    zombieOne.CurrentState = PlayerState.PSTATE_WALKING;
            //}
            //else
            //    zombieOne.CurrentState = PlayerState.PSTATE_WALKING;

        }


        #region ActionEvents Thrown by Actors
        public void Player_DoMeleeAttack(BaseActor Actor)
        {
            Vector3 distance;
            //check to see if player hit any monsters
            //if so, then
            foreach (Monster monster in monsters)
            {
                if (!monster.IsDead)
                {
                    distance = monster.Pos - player.Pos;
                    distance.Y = 0f;
                    if (distance.Length() < 100f)
                    {
                        playerHitComboCounter++;
                        comboTimeUp = Constants.COMBO_TIME;

                        //super hit?
                        if (playerHitComboCounter == 3)
                        {
                            monster.Info_Damage(player, 150);
                            Audio.PlayCue("PUNCH");
                            playerHitComboCounter = 0;
                        }
                        else
                        {
                            monster.Info_Damage(player, 5);
                            Audio.PlayCue("PUNCH");
                        }
                    }
                }
            }
            //1. play sound
            //2. cause damage to the one player hit
        }

        public void Enemy_DoMeleeAttack(BaseActor Actor)
        {
            //check to see if monster hit the player
            //if so, then
            //1. play sound
            //2. cause damage to the player

            playerHitComboCounter = 0;  //reset the counter
            comboTimeUp = 0f;

        }
        #endregion

        /// <summary>
        /// Checks to see if the player has passed any triggers in his
        /// travels across the gameboard
        /// </summary>
        void CheckTriggers()
        {
        }

        #region GameState Specific Methods
        void GameState_Playing(GameTime gameTime, float elapsedTime)
        {
            ApplyGravity();
            CheckCollisions();
            UpdatePositions();

            ZeroForces();

            player.Update(gameTime);

            comboTimeUp -= elapsedTime;
            if (comboTimeUp < 0f)
            {
                playerHitComboCounter = 0;
                comboTimeUp = 0f;
            }

            foreach (Monster monster in monsters)
            {
                monster.Update(gameTime);
            }

            CheckActions();
            FireEvents();

            GamePadState gpadState = GamePad.GetState(PlayerIndex.One);

            if (InputManager.Instance.Pressed(Buttons.START))
            {
                currentGameState = GameStates.PAUSED;
                previousGameState = GameStates.PLAYING;
            }
        }

        void GameState_Paused(float elapsedTime)
        {
            if (InputManager.Instance.Pressed(Buttons.START))
            {
                currentGameState = previousGameState;
                previousGameState = GameStates.PAUSED;
                overlay = null;
            }
            else
            {
                overlay = content.Load<Texture2D>(@"Data\Images\pause_overlay");
            }
        }
        #endregion

        #region DEBUG ROUTINES
        public void Debug_DrawCollisionBox(GraphicsDevice device, BaseActor Actor)
        {
            device.RenderState.PointSize = 4;
            BoundingBox bbox = Actor.BoundingBox;
            Vector3 min = bbox.Min;
            Vector3 max = bbox.Max;

            Vector3 fll = min;
            Vector3 flr = new Vector3(max.X, min.Y, min.Z);
            Vector3 fur = new Vector3(max.X, max.Y, min.Z);
            Vector3 ful = new Vector3(min.X, max.Y, min.Z);

            Vector3 bll = new Vector3(min.X, min.Y, max.Z);
            Vector3 blr = new Vector3(max.X, min.Y, max.Z);
            Vector3 bur = max;
            Vector3 bul = new Vector3(min.X, max.Y, max.Z);

            for (int i = 0; i < 8; i++)
            {
                debug_vertices[i].Normal = Vector3.Forward;
                debug_vertices[i].TextureCoordinate = Vector2.Zero;
            }

            debug_vertices[0].Position = fll;
            debug_vertices[1].Position = flr;
            debug_vertices[2].Position = fur;
            debug_vertices[3].Position = ful;
            debug_vertices[4].Position = bll;
            debug_vertices[5].Position = blr;
            debug_vertices[6].Position = bur;
            debug_vertices[7].Position = bul;

            // Initialize an array of indices of type short.
            //debug_lineListIndices = new short[(8 * 2)];

            // Populate the array with references to indices in the vertex buffer


            //device.DrawUserIndexedPrimitives<VertexPositionNormalTexture>(
            //PrimitiveType.LineList,
            //debug_vertices,
            //0,  // vertex buffer offset to add to each element of the index buffer
            //9,  // number of vertices in pointList
            //debug_lineListIndices,  // the index buffer
            //0,  // first index element to read
            //8   // number of primitives to draw

            device.DrawUserPrimitives<VertexPositionNormalTexture>(
            PrimitiveType.PointList,
            debug_vertices,
            0,  // index of the first vertex to draw
            8   // number of primitives
            );

        }
        #endregion

        #region Collision Routines

        /// <summary>
        /// Apply Gravity to all the objects in the world.
        /// </summary>
        void ApplyGravity()
        {
            player.Vel -= new Vector3(0, 4f, 0);

            foreach (Monster monster in monsters)
            {
                monster.Vel -= new Vector3(0, 4f, 0);
            }

        }


        void ZeroForces()
        {
            //player.Vel = Vector3.Zero;
            player.Vel = new Vector3(0, player.Vel.Y, 0);
            foreach (Monster monster in monsters)
            {
                monster.Vel = new Vector3(0, monster.Vel.Y, 0);
            }
        }

        void UpdatePositions()
        {
            player.Pos += player.Vel;
            //zombieOne.Pos += zombieOne.Vel;
            foreach (Monster monster in monsters)
            {
                monster.Pos += monster.Vel;
            }
        }

        /// <summary>
        /// Starting point for the check collisions routines
        /// </summary>
        public void CheckCollisions()
        {
            //Gravity Check
            if ((player.Pos.Y + player.Vel.Y) < 64)
            {
                player.Pos = new Vector3(player.Pos.X, 65, player.Pos.Z);
                player.Vel = new Vector3(player.Vel.X, 0, player.Vel.Z);
            }

            foreach (Monster monster in monsters)
            {
                if ((monster.Pos.Y + monster.BoundingBox.Min.Y + monster.Vel.Y) < 0)
                {
                    monster.Pos = new Vector3(monster.Pos.X, (monster.BoundingBox.Max.Y + monster.BoundingBox.Min.Y) / 2.0f + 65, monster.Pos.Z);
                    monster.Vel = new Vector3(monster.Vel.X, 0, monster.Vel.Z);
                }
            }

            CheckWorldCollision(player);
            CheckPlayerAgainstOtherBodies();
            CheckEnemyAgainstBodies();
            CheckPlayerAgainstItems();
        }

        bool CheckWorldCollision(BaseActor actor)
        {

            Matrix actorTransformMatrix;
            Vector3 actorPosition = actor.Pos;
            Vector3 actorVelocity = actor.Vel;

            Vector3 tempActorPosition = actor.Pos;

            Vector3 newActorPosition = actor.Pos;
            Vector3 newActorVelocity = actor.Vel;

            BoundingBox tempActorBBox;

            bool collision = false;

            foreach (ZombieHigh2.DeleD.Primitive3D prim in parser.Primitives)
            {
                collision = false;

                actorPosition = actor.Pos;
                actorVelocity = actor.Vel;
                tempActorPosition = actor.Pos;
                //foreach (Polygon poly in prim.polygons)
                //{
                BoundingBox worldbbox = prim.BBox;
                BoundingBox actorbbox = actor.BoundingBox;

                //Check X Direction
                tempActorPosition.X += actor.Vel.X;
                actorTransformMatrix = Matrix.CreateTranslation(tempActorPosition);
                tempActorBBox = new BoundingBox(Vector3.Transform(actorbbox.Min, actorTransformMatrix), Vector3.Transform(actorbbox.Max, actorTransformMatrix));

                if (tempActorBBox.Intersects(worldbbox))
                {
                    if (actorVelocity.X > 0)
                    {
                        newActorVelocity.X = 0;
                        newActorPosition.X = worldbbox.Min.X - actor.Width / 2 - 1; ;
                    }
                    else if (actorVelocity.X < 0)
                    {
                        newActorVelocity.X = 0;
                        newActorPosition.X = worldbbox.Max.X + actor.Width / 2 + 1;
                    }

                    collision = true;
                }

                //Check X Direction
                tempActorPosition = actorPosition;
                tempActorPosition.Z += actor.Vel.Z;
                actorTransformMatrix = Matrix.CreateTranslation(tempActorPosition);
                tempActorBBox = new BoundingBox(Vector3.Transform(actorbbox.Min, actorTransformMatrix), Vector3.Transform(actorbbox.Max, actorTransformMatrix));

                if (tempActorBBox.Intersects(worldbbox))
                {
                    if (actorVelocity.Z > 0)
                    {
                        newActorVelocity.Z = 0;
                        newActorPosition.Z = worldbbox.Min.Z - actor.Depth / 2 - 1;
                    }
                    else if (actorVelocity.Z < 0)
                    {
                        newActorVelocity.Z = 0;
                        newActorPosition.Z = worldbbox.Max.Z + actor.Depth / 2 + 1;
                    }

                    collision = true;
                }
                //}

                if (collision)
                {
                    actor.Pos = newActorPosition;
                    actor.Vel = newActorVelocity;
                }
            }

            //if (collision)
            //{
            //    actor.Pos = newActorPosition;
            //    actor.Vel = newActorVelocity;
            //}

            return collision;
        }

        bool CheckGeneralCollision(BaseActor main, BaseActor target)
        {
            Vector3 oldVelocity = main.Vel;
            Vector3 oldPosition = main.Pos;
            BoundingBox collisionBox = main.CollisionBox;
            BoundingBox tempBox;
            Vector3 tempPosition;
            Vector3 newVelocity = main.Vel;
            Vector3 newPosition = main.Pos;
            bool Collision = false;

            Matrix transform;

            tempPosition = main.Pos;
            tempPosition.X += main.Vel.X;
            transform = Matrix.CreateTranslation(tempPosition);
            tempBox = new BoundingBox(Vector3.Transform(main.BoundingBox.Min, transform),
                Vector3.Transform(main.BoundingBox.Max, transform));

            if (tempBox.Intersects(target.CollisionBox))
            {
                if (tempBox.Max.X > target.CollisionBox.Min.X && main.Vel.X > 0)
                {
                    newVelocity.X = 0f;
                    newPosition.X = target.CollisionBox.Min.X - main.Width / 2 - 1;
                    //newPosition.X = oldPosition.X - (tempBox.Max.X - target.CollisionBox.Min.X) + 1f;
                }
                else if (tempBox.Min.X < target.CollisionBox.Max.X && main.Vel.X < 0)
                {
                    newVelocity.X = 0f;
                    newPosition.X = target.CollisionBox.Max.X + main.Width / 2 + 1;
                    //newPosition.X = oldPosition.X + (target.CollisionBox.Max.X - tempBox.Min.X) - 1;
                }

                Collision = true;
            }

            tempPosition = main.Pos;
            tempPosition.Z += main.Vel.Z;
            transform = Matrix.CreateTranslation(tempPosition);
            tempBox = new BoundingBox(Vector3.Transform(main.BoundingBox.Min, transform),
                Vector3.Transform(main.BoundingBox.Max, transform));

            if (tempBox.Intersects(target.CollisionBox))
            {
                if (tempBox.Max.Z > target.CollisionBox.Min.Z && main.Vel.Z > 0)
                {
                    newVelocity.Z = 0f;
                    newPosition.Z = target.CollisionBox.Min.Z - main.Depth / 2 - 1;
                }
                else if (tempBox.Min.Z < target.CollisionBox.Max.Z && main.Vel.Z < 0)
                {
                    newVelocity.Z = 0f;
                    newPosition.Z = target.CollisionBox.Max.Z + main.Depth / 2 + 1f;
                }

                Collision = true;
            }

            if (Collision)
            {
                main.Pos = newPosition;
                main.Vel = newVelocity;
            }

            return Collision;
        }

        void CheckEnemyAgainstBodies()
        {
            foreach (Monster monster in monsters)
            {
                if (!monster.IsDead)
                {
                    foreach (Monster targetmonster in monsters)
                    {
                        if (targetmonster != monster)
                        {
                            CheckGeneralCollision(monster, targetmonster);
                        }
                    }

                    CheckGeneralCollision(monster, player);
                }
            }
        }

        void CheckPlayerAgainstOtherBodies()
        {

            foreach (Monster monster in monsters)
            {
                if (!monster.IsDead)
                {
                    CheckGeneralCollision(player, monster);
                }
            }
        }

        void CheckPlayerAgainstItems()
        {
            List<WorldItem> removals = new List<WorldItem>();
            Matrix playerTranslation = Matrix.CreateTranslation(player.Pos);
            Matrix itemTranslation;
            BoundingSphere itemSphere;
            BoundingBox playerBox = new BoundingBox(Vector3.Transform(player.BoundingBox.Min, playerTranslation),
                Vector3.Transform(player.BoundingBox.Max, playerTranslation));

            foreach (WorldItem witem in worldItems)
            {
                itemTranslation = Matrix.CreateTranslation(witem.Position);
                itemSphere = new BoundingSphere(Vector3.Transform(witem.BoundingSphere.Center, itemTranslation),
                    witem.BoundingSphere.Radius);
                if (itemSphere.Intersects(playerBox))
                {
                    player.TouchItem(witem.ItemType);
                    removals.Add(witem);
                    break;
                }
            }

            foreach (WorldItem remove in removals)
            {
                worldItems.Remove(remove);
            }
        }
        #endregion
    }
}
